import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import { useMessageStore } from '@/store/modules/eventBus'
import { useUserStore } from '@/store/modules/user'
const baseURL = import.meta.env.VITE_baseUrl

const { useMessage } = useMessageStore()
//使用指定配置创建axios实例
const instance = axios.create({ baseURL })

/** 定义接口，用来规范返回的数据格式 */
type Response<T = any> = {
  /** 描述 */
  message: string
  /** 状态码 */
  code: number
  /** 数据 */
  data: T
}

// AxiosRequestConfig从axios中导出的，将config声明为AxiosRequestConfig，这样我们调用函数时就可以获得TS带来的类型提示
// 泛型T用来指定Reponse类型中result的类型
const defaultRequst = <T>(config: AxiosRequestConfig) => {
  // 指定promise实例成功之后的回调函数的第一个参数的类型为Response<T>
  return new Promise<T>((resolve, reject) => {
    instance
      .request<Response<T>>(config)
      .then((response: AxiosResponse<Response<T>>) => {
        const { data } = response

        if (data.code === 200) {
          resolve(data.data)
        } else if (data.code === 401 || data.code === 403) {
          // token过期
          useMessage({ content: '登录状态失效,请重新登录', type: 'error' })
          useUserStore().removeUserInfo()
          reject(data.message)
        } else {
          // 请求失败的处理
          useMessage({ content: data.message, type: 'error' })
          reject(data.message)
        }
      })
      .catch((error: any) => {
        // 请求失败的处理
        reject(error)

        if (error.response.status === 401 || error.response.status === 403) {
          // token过期
          useMessage({ content: '登录状态失效,请重新登录', type: 'error' })
          useUserStore().removeUserInfo()
          reject(error.response.data.message)
        }
      })
  })
}

interface RequestConfig {
  /** 请求的url */
  url: string
  /** 请求的参数 */
  params?: any
  /** 请求的数据 */
  data?: any
  /** 请求的方法 */
  method?: AxiosRequestConfig['method']
  /** 是否需要token */
  notUseToken?: boolean
  /** 是否需要超时 */
  notTimeOut?: boolean
  /** 响应类型 */
  responseType?: AxiosRequestConfig['responseType']
}
/**
 * @description: 通用的请求方法
 * @param {string} config.url 请求的url
 * @param {any} config.params 请求的参数
 * @param {any} config.data 请求的数据
 * @param {AxiosRequestConfig['method']} config.method 请求的方法
 * @param {boolean} config.notUseToken 是否需要token
 * @param {boolean} config.notTimeOut 是否需要超时
 * @return {Promise<T>} 返回一个promise对象，泛型T用来指定返回的数据的类型
 */
export default <T>({
  url = '',
  params = {},
  data = {},
  method = 'post',
  responseType = 'json',
  notUseToken = false,
  notTimeOut = false,
}: RequestConfig): Promise<T> => {
  const deleteEmptyProperty = (obj: any) => {
    Object.keys(obj).forEach(key => {
      if (obj[key] === '' || obj[key] === undefined) {
        delete obj[key]
      } else if (typeof obj[key] === 'string') {
        ;(obj[key] as string).trim()
      }
    })
  }

  // 去除对象中值为空的属性
  if (method === 'get') {
    deleteEmptyProperty(params)
  } else {
    deleteEmptyProperty(params)
    deleteEmptyProperty(data)
  }

  // 在这里可以对请求进行一些处理，例如添加token等操作
  const headers: any = {}
  const { token } = useUserStore()
  if (!notUseToken) {
    headers['authorization'] = token
  }

  // 设置超时时间,超过5秒就报错
  const timeout = notTimeOut ? 0 : 5000

  return defaultRequst<T>({ url, method, data, params, headers, timeout, responseType })
}
